package solutions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.pi4.locutil.GeoPosition;
import org.pi4.locutil.MACAddress;
import org.pi4.locutil.Statistics;
import org.pi4.locutil.io.TraceGenerator;
import org.pi4.locutil.trace.Parser;
import org.pi4.locutil.trace.TraceEntry;

import solutions.MainAlgorithmRunner.TraceEstimater;

public abstract class BasePositioner implements TraceEstimater {
	protected static Parser offlineParser;
	protected static Parser onlineParser;
	protected TraceGenerator tg;
	protected List<Double> differences = new LinkedList<Double>();
	protected List<EntryWithMACsAndAverages> offlineEntries = new ArrayList<EntryWithMACsAndAverages>();
	protected int k;

	public void printStats() {

		System.out.println("Average Mean In Meters: "
				+ Statistics.avg(differences) + " variance "
				+ Statistics.var(differences) + " std. deviation: "
				+ Statistics.stdDev(differences) + " median: "
				+ Statistics.median(differences));
	}

	public GeoPosition estimatePosition(TraceEntry onlineentry) {
		EntryWithMACsAndAverages onlineAverage = new EntryWithMACsAndAverages(
				onlineentry);
		for (EntryWithMACsAndAverages entry : offlineEntries) {
			double distance = 0;
			for (MACAddress address : onlineAverage.addresses.keySet()) {
				if (entry.addresses.containsKey(address)) {
					double newDistance = PositionUtils.getDistance(
							onlineAverage.addresses.get(address),
							entry.addresses.get(address));
					distance += newDistance;
				} else {
					distance += 20;
				}
			}

			for (MACAddress address : entry.addresses.keySet()) {
				if (!onlineAverage.addresses.containsKey(address))
					distance += 20;
			}

			entry.distance = distance;
		}

		Collections.sort(offlineEntries);
		double estimateX = 0, estimateY = 0, estimateZ = 0;
		List<EntryWithMACsAndAverages> entries = offlineEntries.subList(0, k);
		for (int i = 0; i < k; i++) {
			estimateX = estimateX + entries.get(i).getPosition().getX();
			estimateY = estimateY + entries.get(i).getPosition().getY();
			estimateZ = estimateZ + entries.get(i).getPosition().getZ();
		}
		estimateX = estimateX / k;
		estimateY = estimateY / k;
		estimateZ = estimateZ / k;
		return new GeoPosition(estimateX, estimateY, estimateZ);
	}
}
